﻿using System;
using System.Collections.Generic;
using Development.DataEntity;
using Development.DbData;
using Development.Redis;

namespace Development.Factory
{
    /// <summary>
    /// factory 基类
    /// </summary>
    public class FactoryDataBase
    {
        protected Dictionary<string, DataContainer> _containers = new Dictionary<string, DataContainer>();
        protected readonly object _flagLock = new object();
        protected bool _isCache = false;
        public virtual void Init()
        {

        }

        /// <summary>
        /// 由于初始化时已经确定了容器，所有后面不用加锁
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        protected DataContainer GetContainer<T>()
        {
            string key = typeof(T).Name;
            if(!_containers.ContainsKey(key))
            {
                _containers.Add(key, new DataContainer());
            }
            return _containers[key]; ;
        }

        protected void CreateContainers(Type baseType,bool isCache = false)
        {
            _isCache = isCache;
            List<Type> types = DbDataHelper.GetTypesFromCurrAssemblyByBase(baseType);
            for(int i = 0; i < types.Count; ++i)
            {
               Type type = types[i];
                //检查数据库
               List<DataEntityBase> dbDatas = DbDataHelper.GetDbEntityList(type);
               DataContainer container = null;
               if(_isCache)
               {
                   container = new DataContainer();
                   _containers.Add(type.Name, container);
               }
               for (int j = 0; j < dbDatas.Count; ++j)
               {
                   DataEntityBase dt = dbDatas[j];
                   if (dt != null)
                   {
                       RedisManager.Instance.Set(dt.GetType().Name, dt.GetRedisKey(), dt);
                       if(_isCache)
                       {
                           container.Add(dt.ID, dt);
                       }
                   }
                }
            }
        }

        public virtual T FindKey<T>(long id) where T : DataEntityBase,new ()
        {
            T t = null;
            if(_isCache)
            {
                t = GetContainer<T>().Get<T>(id);
                if (t != null)
                {
                    t.UseTime = DateTime.Now;
                    return t;
                }
            }
            //先从redis查找
            t = RedisManager.Instance.Get<T>(DataEntityBase.GetRedisKey<T>(id));
            //再从数据库查找
            if (t == null)
            {
                DbProviderManager.Instance.ExecuteQuery(DataEntityBase.GetDbName<T>(), p =>
                {
                    t = DbDataHelper.GetDbEntity<T>(p, id);
                    if (t != null)
                    {
                        RedisManager.Instance.Set<T>(t.GetRedisKey(), t);
                    }
                });
            }
            if (_isCache)
            {
                if (t != null)
                {
                    t.UseTime = DateTime.Now;
                    GetContainer<T>().Add(t.ID, t);
                }
            }
            return t;
        }
        public virtual List<T> FindKeys<T>(List<long> ids) where T : DataEntityBase, new()
        {
            if(ids.Count == 0)
            {
                return new List<T>();
            }
            List<T> list = null;
            if (_isCache)
            {
                list = GetContainer<T>().Get<T>(ids);
                if (list.Count != 0)
                {
                    return list;
                }
            }
            list = RedisManager.Instance.Get<T>(DataEntityBase.GetRedisKeys<T>(ids));
            if(list.Count == 0)
            {
                list = DbDataHelper.GetDbEntityList<T>(ids);
                RedisManager.Instance.Set<T>(typeof(T).Name, list);
            }
            if(_isCache)
            {
                for (int i = 0; i < list.Count; ++i)
                {
                    DataEntityBase t = list[i];
                    GetContainer<T>().Add(t.ID, t);
                }
            }
            return list;
        }


        public virtual void AddEntity<T>(T t) where T : DataEntityBase, new()
        {
            if (_isCache)
            {
                t.UseTime = DateTime.Now;
                GetContainer<T>().Add<T>(t.ID, t);
            }
            //先更新db
            DbProviderManager.Instance.AddSql(t.GetDbName(), DbDataHelper.GetEntityInsertSql(t));
            //更新redis
            RedisManager.Instance.Set<T>(t.GetRedisKey(), t);
        }

        public virtual void RemoveEntity<T>(T t) where T : DataEntityBase, new()
        {
            if (_isCache)
            {
                GetContainer<T>().Remove<T>(t.ID);
            }
            //先更新db
            DbProviderManager.Instance.AddSql(t.GetDbName(), DbDataHelper.GetEntityDeleteSql(t));
            //更新redis
            RedisManager.Instance.Remove<T>(t.GetRedisKey());
        }

        public virtual void RemoveEntitys<T>(List<T> ts) where T : DataEntityBase
        {
            if (_isCache)
            {
                GetContainer<T>().Remove<T>(ts);
            }
            //先更新db
            DbDataHelper.RemoveIds<T>(ts);
            //更新redis
            List<string> keys = new List<string>();
            for (int i = 0; i < keys.Count;++i )
            {
                keys.Add(ts[i].GetRedisKey());
            }
            RedisManager.Instance.Remove<T>(keys);
        }

        public virtual List<T> FindAll<T>() where T : DataEntityBase, new()
        {
            List<T> list = null;
            if (_isCache)
            {
                list = GetContainer<T>().GetAll<T>();
                if (list.Count != 0)
                {
                    return list;
                }
            }

            list = RedisManager.Instance.GetAll<T>();
            if (list.Count == 0)
            {
                DbProviderManager.Instance.ExecuteQuery(DataEntityBase.GetDbName<T>(), p =>
                {
                    list = DbDataHelper.GetDbEntityList<T>(p);
                    if (list.Count != 0)
                    {
                        for (int i = 0; i < list.Count; ++i)
                        {
                            RedisManager.Instance.Set<T>(list[i].GetRedisKey(), list[i]);
                        }
                    }
                });
            }
            if (_isCache)
            {
                for (int i = 0; i < list.Count; ++i)
                {
                    DataEntityBase t = list[i];
                    GetContainer<T>().Add(t.ID, t);
                }
            }
            return list;
        }

        public virtual List<T> FindAll<T>(Predicate<T> match) where T : DataEntityBase, new()
        {
            List<T> list = FindAll<T>();
            return list.FindAll(match);
        }

        public virtual void Set<T>(T t) where T : DataEntityBase, new()
        {
            if (_isCache)
            {
                t.UseTime = DateTime.Now;
            }
            //先更新db
            DbProviderManager.Instance.AddSql(t.GetDbName(), DbDataHelper.GetEntityUpdateSql(t));
            //更新redis   
            RedisManager.Instance.Set<T>(t.GetRedisKey(), t);
        }

        public virtual void RemoveAll<T>() where T : DataEntityBase, new()
        {
            if (_isCache)
            {
                GetContainer<T>().Clear();
            }
            DbProviderManager.Instance.AddSql(DataEntityBase.GetDbName<T>(), "delete from " + typeof(T).Name);
            RedisManager.Instance.RemoveAll<T>();
        }

        public virtual void RemoveAll<T>(Predicate<T> match) where T : DataEntityBase, new()
        {
            List<T> list = FindAll<T>(match);
            for (int i = 0; i < list.Count; ++i)
            {
                RemoveEntity(list[i]);
            }
        }

        public virtual List<long> GetKeys<T>() where T : DataEntityBase
        {
            if (_isCache)
            {
                return GetContainer<T>().GetKeys<T>();
            }
            List<long> list = new List<long>();
            var keys = RedisManager.Instance.GetKeys<T>();
            for(int i = 0; i < keys.Count;++i)
            {
                list.Add(DataEntityBase.GetKeyFromRedis(keys[i]));
            }
            if(list.Count == 0)
            {
               DbProviderManager.Instance.ExecuteQuery(DataEntityBase.GetDbName<T>(), p =>
              {
                  long tempId = 0;
                  string sql = string.Format("select ID from {0}", typeof(T).Name);
                  if(p.ExecuteQuery(sql))
                  {
                      while(p.Read())
                      {
                          p.Read(ref tempId);
                          list.Add(tempId);
                      }
                  }
              });
            }
            return list;
        }

        /// <summary>
        /// 获取某页的数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pageIndex"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public List<T> GetPageList<T>(int pageIndex, int count) where T : RankingEntity
        {
            var temp = GetContainer<T>().GetAll<T>();
            int startRank = pageIndex * count + 1;
            int endRank = (pageIndex + 1) * count;
            List<T> list = new List<T>();
            for (int i = 0; i < temp.Count; ++i)
            {
                var entity = temp[i];
                if (entity.Rank >= startRank && entity.Rank <= endRank)
                {
                    if (list.Count < count)
                    {
                        list.Add(entity);
                    }
                    else
                    {
                        break;
                    }
                }
            }
            list.Sort();
            return list;
        }


    }
}
